import * as hash from "../hash/index.js";
import * as utils from "../utils.js";
import assert from "assert";
'use strict';
function HmacDRBG(options) {
    if (!(this instanceof HmacDRBG))
        return new HmacDRBG(options);
    this.hash = options.hash;
    this.predResist = !!options.predResist;
    this.outLen = this.hash.outSize;
    this.minEntropy = options.minEntropy || this.hash.hmacStrength;
    this._reseed = null;
    this.reseedInterval = null;
    this.K = null;
    this.V = null;
    var entropy = utils.toArray(options.entropy, options.entropyEnc || 'hex');
    var nonce = utils.toArray(options.nonce, options.nonceEnc || 'hex');
    var pers = utils.toArray(options.pers, options.persEnc || 'hex');
    assert(entropy.length >= (this.minEntropy / 8), 'Not enough entropy. Minimum is: ' + this.minEntropy + ' bits');
    this._init(entropy, nonce, pers);
}
HmacDRBG.prototype._init = function init(entropy, nonce, pers) {
    var seed = entropy.concat(nonce).concat(pers);
    this.K = new Array(this.outLen / 8);
    this.V = new Array(this.outLen / 8);
    for (var i = 0; i < this.V.length; i++) {
        this.K[i] = 0x00;
        this.V[i] = 0x01;
    }
    this._update(seed);
    this._reseed = 1;
    this.reseedInterval = 0x1000000000000; // 2^48
};
HmacDRBG.prototype._hmac = function hmac() {
    return new hash.hmac(this.hash, this.K);
};
HmacDRBG.prototype._update = function update(seed) {
    var kmac = this._hmac()
        .update(this.V)
        .update([0x00]);
    if (seed)
        kmac = kmac.update(seed);
    this.K = kmac.digest();
    this.V = this._hmac().update(this.V).digest();
    if (!seed)
        return;
    this.K = this._hmac()
        .update(this.V)
        .update([0x01])
        .update(seed)
        .digest();
    this.V = this._hmac().update(this.V).digest();
};
HmacDRBG.prototype.reseed = function reseed(entropy, entropyEnc, add, addEnc) {
    // Optional entropy enc
    if (typeof entropyEnc !== 'string') {
        addEnc = add;
        add = entropyEnc;
        entropyEnc = null;
    }
    entropy = utils.toArray(entropy, entropyEnc);
    add = utils.toArray(add, addEnc);
    assert(entropy.length >= (this.minEntropy / 8), 'Not enough entropy. Minimum is: ' + this.minEntropy + ' bits');
    this._update(entropy.concat(add || []));
    this._reseed = 1;
};
HmacDRBG.prototype.generate = function generate(len, enc, add, addEnc) {
    if (this._reseed > this.reseedInterval)
        throw new Error('Reseed is required');
    // Optional encoding
    if (typeof enc !== 'string') {
        addEnc = add;
        add = enc;
        enc = null;
    }
    // Optional additional data
    if (add) {
        add = utils.toArray(add, addEnc || 'hex');
        this._update(add);
    }
    var temp = [];
    while (temp.length < len) {
        this.V = this._hmac().update(this.V).digest();
        temp = temp.concat(this.V);
    }
    var res = temp.slice(0, len);
    this._update(add);
    this._reseed++;
    return utils.encode(res, enc);
};
export default HmacDRBG;
